package network.socket;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Vector;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import network.NetworkConstants;
import network.RSocket;
import network.byteConversions.ByteConverter;
import network.dataFormats.NetworkData;

import tools.Help;
import tools.Log;
import tools.Profiler;
public class TCPClient extends RSocket {
	private Socket sock;
	private OutputStream out;
	private InputStream in;
	public String address;
	public int port;
	private byte[] sendarray = new byte[NetworkConstants.PACKAGESIZE + 40];
	private byte[] rdata = new byte[NetworkConstants.PACKAGESIZE + 40];
	private int cplength;
	public TCPClient(String address, int port) {
		try {
			sock = new Socket(address, port);
			//sock.setTcpNoDelay(true);
			out = sock.getOutputStream();
			in = sock.getInputStream();
			this.address = address;
			this.port = port;
		} catch (UnknownHostException e) {
			Help.p(e.getMessage());
			System.exit(1);
		} catch (IOException e) {
			Help.p(e.getMessage());
			System.exit(1);
		}
	}
	public TCPClient(Socket sock) {
		try {
			this.sock = sock;
			//sock.setTcpNoDelay(true);
			out = sock.getOutputStream();
			sock.setSendBufferSize(NetworkConstants.PACKAGESIZE);
			sock.setReceiveBufferSize(NetworkConstants.PACKAGESIZE);
			Help.p("recv size:" + sock.getReceiveBufferSize());
			Help.p("send size:" + sock.getSendBufferSize());
			in = sock.getInputStream();
			if(sock.getReceiveBufferSize() < NetworkConstants.PACKAGESIZE) Help.p("Warning: Specified receive-packagesize is not provided by your system!");
			if(sock.getSendBufferSize() < NetworkConstants.PACKAGESIZE) Help.p("Warning: Specified send-packagesize is not provided by your system!");	
			this.address = sock.getInetAddress().getCanonicalHostName();
			this.port = sock.getPort();
		} catch (IOException e) {
			Help.p(e.getMessage());
		} 
	}
	public void send(byte b[]) {
		try {
			if (b.length < sendarray.length) {
				ByteConverter.intToFourBytes(b.length, sendarray, 0);
				if(NetworkConstants.PRINTLOG) Log.n("send: " + (b.length + 4));
				for (int i = 4; i < b.length + 4; i++) {
					sendarray[i] = b[i - 4];
				}
				// Help.p("send: "+b.length);
				// out.writeInt(b.length);
				out.write(sendarray, 0, b.length + 4);
				out.flush();
			}
			else {
				Help.p("You want to send too large arrays!");
			}
		} catch (IOException e) {
			Help.p("Error while sending message! " + e.getLocalizedMessage());
			if (e.getLocalizedMessage().equals("Broken pipe")) {
				Help.p("connection offline. Stopping.");
				System.exit(1);
			}
		} 
	}
	public byte[] getReceiveData() {
		try {
			sock.setSoTimeout(1);
			in.read(rdata, 0, 4);
			int s = ByteConverter.bytesToInt(rdata);
			if(NetworkConstants.PRINTLOG) Log.n("recv:" + s);
			if (s > 0 && s < NetworkConstants.PACKAGESIZE + 4) {
				s = in.read(rdata, 0, s);
				return Arrays.copyOfRange(rdata, 0, s);
			}
			else {
				Help.p("wrong package size: " + s);
			}
		} catch (IOException e) {
		}
		return null;
	}
	public void close() {
		try {
			sock.close();
		} catch (IOException e) {
		}
	}
	@Override
	public void sendData(Vector<NetworkData> outgoing) {
		for (NetworkData d : outgoing) {
			this.send(d.data);
		}
	}
	@Override
	public Vector<NetworkData> popData() {
		Vector<NetworkData> rd = new Vector<NetworkData>();
		byte rb[] = this.getReceiveData();
		while (rb != null) {
			Profiler.cnumPackages++;
			Profiler.csizePackages += rb.length;
			rd.add(new NetworkData(rb));
			rb = this.getReceiveData();
		}
		return rd;
	}
	@Override
	public void sendUnsecure(Vector<NetworkData> outgoing) {
		for (NetworkData d : outgoing) {
			this.send(d.data);
		}
	}
}
